<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="EhEal" id="EhEal"><span data-lake-id="uc6ef30d2" id="uc6ef30d2">典型回答</span></h1>
  <p data-lake-id="u3eb6575d" id="u3eb6575d"><br></p>
  <p data-lake-id="u1cc3943f" id="u1cc3943f"><code data-lake-id="u735503e9" id="u735503e9"><span data-lake-id="u50f3058e" id="u50f3058e">@TransactionalEventListener</span></code><span data-lake-id="u28358d9f" id="u28358d9f"> 是 Spring Framework 提供的一个注解，用于处理事务事件。</span></p>
  <p data-lake-id="u79cbcdbf" id="u79cbcdbf"><span data-lake-id="u5eb781be" id="u5eb781be">​</span><br></p>
  <p data-lake-id="uec6c53d2" id="uec6c53d2"><span data-lake-id="uce8202be" id="uce8202be">它可以在事务提交前后（或回滚前后）触发事件监听器，以执行一些特定的操作。这个注解的使用场景是在需要基于事务状态执行后处理逻辑时非常有用。</span></p>
  <p data-lake-id="ue1140121" id="ue1140121"><span data-lake-id="u1ac682c5" id="u1ac682c5">​</span><br></p>
  <p data-lake-id="ud50fb5eb" id="ud50fb5eb"><span data-lake-id="u56400345" id="u56400345">Spring事件机制见：</span></p>
  <p data-lake-id="ude3362d6" id="ude3362d6"><span data-lake-id="u01b7093d" id="u01b7093d">​</span><br></p>
  <p data-lake-id="uee38156d" id="uee38156d"><br></p>
  <p data-lake-id="u8e6e40cc" id="u8e6e40cc"><span data-lake-id="uf4bff332" id="uf4bff332">上面链接介绍的Spring Event的使用方式是没有考虑事务的，如果要考虑在事务的过程中发送和处理事件，则可以用</span><code data-lake-id="u5245df61" id="u5245df61"><span data-lake-id="u4336aa98" id="u4336aa98">@TransactionalEventListener</span></code></p>
  <p data-lake-id="u39ebc29f" id="u39ebc29f"><span data-lake-id="u0eb81715" id="u0eb81715">​</span><br></p>
  <p data-lake-id="u3fd70eea" id="u3fd70eea"><span data-lake-id="ud7652002" id="ud7652002">如以下是一个简单的例子：</span></p>
  <p data-lake-id="u7b0ef2ed" id="u7b0ef2ed"><span data-lake-id="ufcf60fb1" id="ufcf60fb1">​</span><br></p>
  <pre lang="java"><code>
@Service
public class UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Transactional
    public void registerUser(User user) {
        // 用户注册逻辑

        // 发布用户注册事件
        UserRegistrationEvent registrationEvent = new UserRegistrationEvent(user);
        eventPublisher.publishEvent(registrationEvent);
    }
}

@Component
public class UserRegistrationEventListener {

    @TransactionalEventListener
    public void handleUserRegistrationEvent(UserRegistrationEvent event) {
        // 事务成功提交后执行的逻辑
        sendWelcomeEmail(event.getUser());
    }

    private void sendWelcomeEmail(User user) {
        // 发送欢迎邮件
    }
}

</code></pre>
  <p data-lake-id="ufb7de4ba" id="ufb7de4ba"><br></p>
  <p data-lake-id="ue9ba3926" id="ue9ba3926"><span data-lake-id="ue704f32f" id="ue704f32f">在上面的示例中，UserRegistrationEvent 事件在用户注册成功后发布，然后 UserRegistrationEventListener 中的 handleUserRegistrationEvent 方法在事务成功提交后触发，发送欢迎邮件。</span></p>
  <p data-lake-id="ue8633eca" id="ue8633eca"><span data-lake-id="uc498bd95" id="uc498bd95">​</span><br></p>
  <p data-lake-id="ud6b2a2b2" id="ud6b2a2b2"><code data-lake-id="ucff08c60" id="ucff08c60"><span data-lake-id="uad1af370" id="uad1af370">TransactionalEventListener</span></code><span data-lake-id="ufebcc926" id="ufebcc926"> 默认只在成功提交的事务中触发事件监听器。如果需要在事务回滚后也触发，可以使用 phase 属性进行配置。</span></p>
  <p data-lake-id="u7cb0a518" id="u7cb0a518"><span data-lake-id="ubfb51331" id="ubfb51331">​</span><br></p>
  <p data-lake-id="u9c9d5056" id="u9c9d5056"><span data-lake-id="u57c45c09" id="u57c45c09">phase 属性用于指定事件监听器的触发时机，它有四种不同的阶段，分别是 BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK 和 AFTER_COMPLETION。它们的区别如下：</span></p>
  <p data-lake-id="ue208bae6" id="ue208bae6"><span data-lake-id="u19a51ddd" id="u19a51ddd">​</span><br></p>
  <ol list="ubc433498">
   <li fid="uf578f687" data-lake-id="ue9d6459b" id="ue9d6459b"><span data-lake-id="ue1786921" id="ue1786921">BEFORE_COMMIT</span><span data-lake-id="uff86a4ef" id="uff86a4ef">：在事务提交前触发。事件监听器将在事务尚未提交时执行，这意味着它可以在事务内部进行回滚操作，如果事件监听器抛出异常，将导致事务回滚。这个阶段通常用于在事务即将提交前执行某些额外的逻辑。</span></li>
   <li fid="uf578f687" data-lake-id="u8100d89e" id="u8100d89e"><span data-lake-id="u3054017b" id="u3054017b">AFTER_COMMIT</span><span data-lake-id="u61e30b99" id="u61e30b99">：在事务成功提交后触发。事件监听器将在事务已成功提交后执行，这意味着它不会影响事务的回滚。这个阶段通常用于执行那些不应该导致事务回滚的后处理操作，如发送通知或记录日志。</span></li>
   <li fid="uf578f687" data-lake-id="ue6d6eebe" id="ue6d6eebe"><span data-lake-id="ud0d65226" id="ud0d65226">AFTER_ROLLBACK</span><span data-lake-id="u9cc550a1" id="u9cc550a1">：在事务回滚后触发。事件监听器将在事务回滚后执行，这通常用于清理或记录与事务回滚相关的操作。</span></li>
   <li fid="uf578f687" data-lake-id="u9adcae09" id="u9adcae09"><span data-lake-id="udec05eab" id="udec05eab">AFTER_COMPLETION：在事务完成（不管是提交还是回滚）后触发。事件监听器将在事务完成后执行，无论事务是否成功提交或回滚。这个阶段通常用于执行一些与事务状态无关的清理工作。</span></li>
  </ol>
  <p data-lake-id="ue3b258d9" id="ue3b258d9"><span data-lake-id="udfe2db4e" id="udfe2db4e">​</span><br></p>
  <p data-lake-id="uc9c8f7dc" id="uc9c8f7dc"><span data-lake-id="u35fa7b26" id="u35fa7b26">​</span><br></p>
 </body>
</html>